
#include <stdint.h>
#include <string.h>

#include "app_util.h"
//#include "app_error.h"

#include "xota+pb.h"
#include "xota+pb+proto.h"
#include "xota+pb.h"


uint32_t xota_pb_deocde_init_cmd(pb_stream_t * p_stream, ota_pb_packet_t* p_ota_pb_packet)
{
	if( p_stream->size > PB_CREATE_COMMAND_SIZE )
		return PBD_ERR_DATA_SIZE; 
	
	uint16_t index = 0;
	uint32_t ret_val = PBD_SUCCESS; 
	
	uint8_t * p_data = p_stream->p_data;
	uint32_t len = p_stream->size; 
	
	while( index < len )
	{
		uint8_t field_len = p_data[ index ]; 
		uint8_t field_type = p_data[ index + 1 ]; 
		
		if( (field_len + index ) > len )
			break; 
		
		switch( field_type )
		{
			case PB_INIT_SIGN:
			{
				if( field_len < 68 ){
					p_ota_pb_packet->has_signed_command = true; 
					p_ota_pb_packet->signed_command.signature_type = (ota_pb_signature_type_t)p_data[ index + 2];
					//p_ota_pb_packet->signed_command.signature.size = p_data[ index + 3]; 
                    p_ota_pb_packet->signed_command.signature.size = field_len - 2; 
					memcpy( p_ota_pb_packet->signed_command.signature.bytes, p_data + index + 3, field_len - 2 ); 
				// save address that command start 
					p_ota_pb_packet->command.init.command_start = (uint32_t)( p_data + index + field_len + 1 );
					p_ota_pb_packet->command.init.command_size = len - (index + field_len + 1 ); 			
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH; 
				}
			}
				break; 
			case PB_INIT_HASH:
				if( field_len > 5 && field_len < 40 )
				{
					p_ota_pb_packet->has_command = true; 
					p_ota_pb_packet->command.init.has_hash = true; 
					p_ota_pb_packet->command.init.hash.hash_type = (ota_hash_type_t) p_data[index + 2 ] ;
					p_ota_pb_packet->command.init.hash.hash.size = field_len - 2; //p_data[ index + 3];
					memcpy( p_ota_pb_packet->command.init.hash.hash.bytes, p_data + index + 3, field_len - 2); 
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
			case PB_INIT_CRC32:
				if( field_len == 5 ){
					p_ota_pb_packet->command.init.has_crc = true; 
					p_ota_pb_packet->command.init.crc32 = uint32_decode( p_data + index + 2 ); 
				}
				else
				{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
			case PB_INIT_DFU_TYPE:
				if( field_len == 5 ){
					p_ota_pb_packet->command.init.has_type = true; 
					p_ota_pb_packet->command.init.type = (ota_pb_fw_type_t) uint32_decode( p_data + index + 2 ); 
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
			case PB_INIT_APP_SIZE:
				if( field_len == 5 ){
					p_ota_pb_packet->command.init.has_app_size = true;
					p_ota_pb_packet->command.init.app_size = uint32_decode( p_data + index + 2 ); 
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
			case PB_INIT_SD_SIZE:
				if( field_len == 5 ){
					p_ota_pb_packet->command.init.has_sd_size = true;
					p_ota_pb_packet->command.init.sd_size = uint32_decode( p_data + index + 2 ); 					
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
			case PB_INIT_BL_SIZE:
				if( field_len == 5 ) {
					p_ota_pb_packet->command.init.has_bl_size = true; 
					p_ota_pb_packet->command.init.bl_size = uint32_decode( p_data + index + 2 ); 
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
			case PB_INIT_FW_VER:
				if( field_len == 5 ) {
					p_ota_pb_packet->command.init.has_fw_version = true; 
					p_ota_pb_packet->command.init.fw_version = uint32_decode( p_data + index + 2 ); 
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
			case PB_INIT_HW_VER:
				if( field_len == 5 ){
					p_ota_pb_packet->command.init.has_hw_version = true; 
					p_ota_pb_packet->command.init.hw_version = uint32_decode( p_data + index + 2 ); 
				}
				else{
					ret_val = PBD_ERR_INVALID_LENGTH;
				}
				break; 
//			case PB_INIT_SD_FWID:
//				if( field_len == 5 ) {
//					if( p_ota_pb_packet->command.init.sd_req_count < 16 )
//					{
//						p_ota_pb_packet->command.init.sd_req[ p_ota_pb_packet->command.init.sd_req_count ++ ] = 
//						uint32_decode( p_data + index + 2 ); 
//					}
//					else{
//						ret_val = NRF_ERROR_INVALID_LENGTH;
//					}
//				}
//				else{
//					ret_val = NRF_ERROR_INVALID_LENGTH;
//				}
//				break; 
			case PB_INIT_APP_FWID:
				if( field_len == 5 )
				{
					p_ota_pb_packet->command.init.has_app_fwid = true; 
					p_ota_pb_packet->command.init.app_fwid = uint32_decode( p_data + index + 2 ); 
				}
				else 
				{
					ret_val = PBD_ERR_INVALID_LENGTH; 
				}
				break; 
			
		}
		
		index += field_len + 1;
		if( ret_val != PBD_SUCCESS )
		{
			return ret_val;
		}
	}
	

	p_ota_pb_packet->has_command = true; 

	return PBD_SUCCESS;
}


uint32_t xota_pb_decode_write_cmd( pb_stream_t * p_stream, ota_pb_write_command_t * p_ota_pb_write)
{
	if( p_stream == NULL  )
		return PBD_ERR_INVALID_PARAMS; 
	
	// align 
	if( ( p_stream->size & 0x03 ) > 0 )
		return PBD_ERR_DATA_SIZE; 
	
	if( p_stream->size < PB_WRITE_COMMAND_MIN_SIZE || p_stream->size > PB_WRITE_COMMAND_SIZE ) 
		return PBD_ERR_INVALID_LENGTH; 
	
	p_ota_pb_write->offset = uint32_decode( p_stream->p_data ); 
	if( ( p_ota_pb_write->offset & 0x03 ) > 0 ) 
		return PBD_ERR_INVALID_PARAMS; 
	
	p_ota_pb_write->p_data = p_stream->p_data + 4; 
	p_ota_pb_write->size 	= p_stream->size - 4; 
	
	return PBD_SUCCESS; 	
}

